(function($, undefined)
{
    //SQL工作台SQL自动补全支持函数
    $.sqlAutocomplete = ($.sqlAutocomplete || {});
    $.extend($.sqlAutocomplete,
    {
        /**
         * 解析SQL自动补全信息。
         *
         * @param editor
         * @param session
         * @param pos
         * @param prefix
         *
         * @return { type : "table" } 或者 { type : "column", table : "..." } 或者 null
         */
        resolveAutocompleteInfo : function(editor, session, pos, prefix, delimiter)
        {
            var autocompleteInfo = {};
            var maxRow = session.getLength() - 1;
            var prependRowMin = (pos.row - 50) < 0 ? 0 : (pos.row - 50);
            var appendRowMax = (pos.row + 50) > maxRow ? maxRow : (pos.row + 50);

            try
            {
                var sql = session.getLine(pos.row);
                var myIndex = pos.column - 1;

                var prependRow = pos.row - 1, appendRow = pos.row + 1;

                //前后最大允许50行
                while(true)
                {
                    var tokens = [];
                    $.sqlAutocomplete.resolveTokens(sql, tokens);

                    var token = $.sqlAutocomplete.findTokenBySqlIndex(tokens, myIndex);
                    var isInToken = $.sqlAutocomplete.isInToken(token, myIndex);

                    autocompleteInfo = $.sqlAutocomplete.resolveTokenAutocompleteInfo(tokens, token, isInToken,
                        delimiter, prefix);

                    if(autocompleteInfo && autocompleteInfo.type == "prepend")
                    {
                        if(prependRow >= prependRowMin)
                        {
                            var prevRowText = session.getLine(prependRow);

                            sql = prevRowText + "\n" + sql;
                            myIndex = prevRowText.length + 1 + myIndex;

                            prependRow--;
                        }
                        else
                            break;
                    }
                    else if(autocompleteInfo && autocompleteInfo.type == "append")
                    {
                        if(appendRow <= appendRowMax)
                        {
                            var nextRowText = session.getLine(appendRow);
                            sql = sql + "\n" + nextRowText;

                            appendRow++;
                        }
                        else
                            break;
                    }
                    else
                        break;
                }
            }
            catch(e){}

            return autocompleteInfo;
        },

        /**
         * 解析SQL自动补全信息。
         *
         * @param tokens
         * @param token
         * @param isInToken
         * @param delimiter 语句分隔符
         * @param tableAlias 如果是列自动补全信息，则指定要查找的表别名
         * @return 	{ type : "table" } 表；
         * 			{ type : "column", table : "..." } 列；
         * 			{ type : "none" } 无；
         * 			{ type : "prepend" } 需要前加SQL语句才能解析
         * 			{ type : "append" } 需要后加SQL语句才能解析
         */
        resolveTokenAutocompleteInfo : function(tokens, token, isInToken, delimiter, prefix)
        {
            var catalogAlias = $.sqlAutocomplete.resolveCatalogAlias(token.value);
            var schemaAlias = $.sqlAutocomplete.resolveSchemaAlias(token.value);
            var tableAlias = $.sqlAutocomplete.resolveTableAlias(token.value);

            if(tokens.length < 1 || !token)
                return { type : "none" };

            //注释
            if(isInToken &&
                ($.sqlAutocomplete.isTokenComment(token) || $.sqlAutocomplete.isTokenString(token)))
                return { type : "none" };

            var prevToken = token;
            if(isInToken)
            {
                prevToken = token.prev;
                //如果没有前置Token，则向上级查找
                if(!prevToken)
                    prevToken = token.parent;
            }

            var prevToken = $.sqlAutocomplete.findToken(prevToken, false,
                $.sqlAutocomplete.isNotTokenComment, false);

            if(!prevToken)
                return { type : "prepend" };

            var isTokenDelimiter = function(token)
            {
                return $.sqlAutocomplete.isTokenTextValue(prevToken, delimiter)
                    || $.sqlAutocomplete.isTokenTextValue(prevToken, ";");
            };

            //SQL分隔符
            if(isTokenDelimiter(prevToken))
                return { type : "none" };

            //别名
            if($.sqlAutocomplete.isTokenTextValue(prevToken, "AS"))
                return { type : "none" };

            //列
            if($.sqlAutocomplete.isTokenKeyword(prevToken, $.sqlAutocomplete.keywordsNextIsColumn))
            {
                var tableTokenPredicate = function(token)
                {
                    if(!$.sqlAutocomplete.isTokenIndentifier(token))
                        return false;

                    if(isTokenDelimiter(token))
                        return false;

                    if(!tableAlias)
                        return true;

                    if($.sqlAutocomplete.isTokenTextValue(token, tableAlias)
                        || $.sqlAutocomplete.isTokenTextValue(token.next, tableAlias))
                        return true;

                    return false;
                };

                if($.sqlAutocomplete.isTokenKeyword(prevToken, "SELECT"))
                {
                    var fromToken = $.sqlAutocomplete.findToken(prevToken, true,
                        function(token)
                        {
                            return $.sqlAutocomplete.isTokenKeyword(token, "FROM")
                                || isTokenDelimiter(token);
                        },
                        true);

                    if(isTokenDelimiter(fromToken))
                        return { type : "none" };

                    var tableToken = $.sqlAutocomplete.findToken(fromToken, true,
                        tableTokenPredicate, true);

                    if(tableToken)
                    {
                        var catalogName = $.sqlAutocomplete.resolveCatalogAlias(tableToken.value);
                        var schemaName = $.sqlAutocomplete.resolveSchemaAlias(tableToken.value);
                        var tableName = tableToken.value.substring(tableToken.value.lastIndexOf(".") + 1);

                        if(isTokenDelimiter(tableToken))
                            return { type : "none" };
                        else
                            return { type : "column", table : tableName,catalog:catalogName,schema:schemaName };
                            //return { type : "column", table : tableToken.value };
                    }
                    else
                        return { type : "append" };
                }
                else if($.sqlAutocomplete.isTokenKeyword(prevToken, "WHERE")
                    || $.sqlAutocomplete.isTokenKeyword(prevToken, "ON")
                    || $.sqlAutocomplete.isTokenKeyword(prevToken, "BY"))
                {
                    var fromToken = $.sqlAutocomplete.findToken(prevToken, false,
                        function(token)
                        {
                            return $.sqlAutocomplete.isTokenKeyword(token, "FROM")
                                || $.sqlAutocomplete.isTokenKeyword(token, "UPDATE")
                                || isTokenDelimiter(token);
                        },
                        true);

                    if(isTokenDelimiter(fromToken))
                        return { type : "none" };

                    var tableToken = $.sqlAutocomplete.findToken(fromToken, true,
                        tableTokenPredicate, true);

                    if(tableToken)
                    {
                        var catalogName = $.sqlAutocomplete.resolveCatalogAlias(tableToken.value);
                        var schemaName = $.sqlAutocomplete.resolveSchemaAlias(tableToken.value);
                        var tableName = tableToken.value.substring(tableToken.value.lastIndexOf(".") + 1);

                        if(isTokenDelimiter(tableToken))
                            return { type : "none" };
                        else
                            return { type : "column", table : tableName,catalog:catalogName,schema:schemaName };
                            // return { type : "column", table : tableToken.value };
                    }
                    else
                        return { type : "prepend" };
                }
                else if($.sqlAutocomplete.isTokenKeyword(prevToken, "SET"))
                {
                    var updateToken = $.sqlAutocomplete.findToken(prevToken, false,
                        function(token)
                        {
                            return $.sqlAutocomplete.isTokenKeyword(token, "UPDATE")
                                || isTokenDelimiter(token);
                        },
                        true);

                    if(isTokenDelimiter(updateToken))
                        return { type : "none" };

                    var tableToken = $.sqlAutocomplete.findToken(updateToken, true,
                        tableTokenPredicate, true);

                    if(tableToken)
                    {
                        if(isTokenDelimiter(tableToken))
                            return { type : "none" };
                        else{
                            var catalogName = $.sqlAutocomplete.resolveCatalogAlias(tableToken.value);
                            var schemaName = $.sqlAutocomplete.resolveSchemaAlias(tableToken.value);
                            var tableName = tableToken.value.substring(tableToken.value.lastIndexOf(".") + 1);
                            //return { type : "column", table : tableToken.value };
                            return { type : "column", table : tableName,catalog:catalogName,schema:schemaName };
                        }


                    }
                    else
                        return { type : "prepend" };
                }
            }

            //表
            if($.sqlAutocomplete.isTokenKeyword(prevToken, $.sqlAutocomplete.keywordsNextIsTable) && catalogAlias && schemaAlias)
                return { type : "table" , catalog: catalogAlias, schema: schemaAlias};

            //数据库
            if ($.sqlAutocomplete.isTokenKeyword(prevToken, $.sqlAutocomplete.keywordsNextIsSchema) && catalogAlias){

                return { type: "schema" , catalog: catalogAlias};
            }

            //数据源
            if($.sqlAutocomplete.isTokenKeyword(prevToken, $.sqlAutocomplete.keywordsNextIsCatalog))
                return { type : "catalog" };


            //列 INTO [table] (...)
            else if($.sqlAutocomplete.isTokenIndentifier(prevToken)
                && $.sqlAutocomplete.isTokenKeyword(prevToken.prev, "INTO"))
            {
                return { type : "column", table : prevToken.value };
            }
            else
                return $.sqlAutocomplete.resolveTokenAutocompleteInfo(tokens, prevToken, true, delimiter, tableAlias);

            return { type : "none" };
        },

        /**
         * 解析catalog别名。
         */
        resolveCatalogAlias : function(columnAccess)
        {
            var catalogAlias = null;
            if(columnAccess)
            {
                var catalogAliasEndIndex = columnAccess.indexOf(".");
                if(catalogAliasEndIndex > 0)
                    catalogAlias = columnAccess.substring(0, catalogAliasEndIndex);
            }

            return catalogAlias;
        },

        /**
         * 解析schema别名。
         */
        resolveSchemaAlias : function(columnAccess)
        {
            var schemaAlias = null;
            if(columnAccess)
            {
                var schemaAliasEndIndex = columnAccess.indexOf(".");
                if(schemaAliasEndIndex > 0)
                    schemaAlias = $.sqlAutocomplete.resolveCatalogAlias(columnAccess.substring(schemaAliasEndIndex+1,columnAccess.length));
            }

            return schemaAlias;
        },

        /**
         * 解析表别名。
         */
        resolveTableAlias : function(columnAccess)
        {
            var tableAlias = null;
            if(columnAccess)
            {
                var tableAliasEndIndex = columnAccess.indexOf(".");
                if(tableAliasEndIndex > 0){
                    tableAlias = $.sqlAutocomplete.resolveSchemaAlias(columnAccess.substring(tableAliasEndIndex+1,columnAccess.length));
                }

            }

            return tableAlias;
        },

        buildCompletions : function(names, prefix, type)
        {
            var completions = [];

            if(!names)
                return completions;

            for(var i=0; i<names.length; i++)
            {
                completions[i] =
                    {
                        name : (prefix ? prefix + names[i] : names[i]),
                        value : (prefix ? prefix + names[i] : names[i]),
                        caption: "",
                        meta: type,
                        score: 100
                    };
            }

            return completions;
        },

        //SQL自动补全涉及的关键字（必须大写）
        keywords :
            {
                "SELECT" : true, "FROM" : true, "LEFT" : true, "RIGHT" : true, "CROSS" : true, "FULL" : true,
                "INNER" : true, "OUTER" : true, "JOIN" : true, "ON" : true, "WHERE" : true,
                "ORDER" : true, "GROUP" : true, "BY" : true, "HAVING" : true, "UNION" : true,
                "INSERT" : true, "INTO" : true, "VALUES" : true,
                "UPDATE" : true, "SET" : true,
                "DELETE" : true, "DROP" : true,
                "ALTER" : true, "DROP" : true, "TABLE" : true, "ADD" : true, "RENAME" : true, "MODIFY" : true,
                "CREATE" : true, "REPLACE" : true, "VIEW" : true, "INDEX" : true, "PROCEDURE" : true,
                "TRIGGER" : true, "FUNCTION" : true
            },

        //SQL语句开始关键字*（必须大写）
        keywordsSqlStart :
            {
                "SELECT" : true, "INSERT" : true, "UPDATE" : true, "DELETE" : true,
                "ALTER" : true, "DROP" : true, "CREATE" : true, "REPLACE" : true, "MERGE" : true,
                "GRANT" : true
            },

        // 下一个Token（注释除外）必定是catalog名称的关键字（必须大写）
        keywordsNextIsCatalog :
            {
                "FROM" : true,
                "JOIN" : true,
                "UPDATE" : true,
                "INTO" : true,
                "TABLE" : true
            },

        // 下一个Token（注释除外）必定是schemas名称的关键字（必须大写）

        keywordsNextIsSchema :
            {
                "FROM" : true,
                "JOIN" : true,
                "UPDATE" : true,
                "INTO" : true,
                "TABLE" : true
            },

        //下一个Token（注释除外）必定是表名称的关键字（必须大写）
        keywordsNextIsTable :
            {
                "FROM" : true,
                "JOIN" : true,
                "UPDATE" : true,
                "INTO" : true,
                "TABLE" : true
            },

        //下一个Token（注释除外）必定是列名称的关键字（必须大写）
        keywordsNextIsColumn :
            {
                "SELECT" : true,
                "WHERE" : true,
                "ON" : true,
                "BY" : true,
                "SET" : true
            },

        isKeyword : function(text, keywords)
        {
            if(!keywords)
                keywords = $.sqlAutocomplete.keywords;

            if(!text)
                return false;

            if($.sqlAutocomplete.maxKeywordLength == null)
                $.sqlAutocomplete.maxKeywordLength = $.sqlAutocomplete.getMaxKeywordLength($.sqlAutocomplete.keywords);

            if(text.length > $.sqlAutocomplete.maxKeywordLength)
                return false;

            if(typeof(keywords) == "string")
                return keywords == text.toUpperCase();
            else
                return keywords[text.toUpperCase()];
        },

        getMaxKeywordLength : function(keywords)
        {
            var maxLength = 0;

            for(var k in keywords)
            {
                if(k.length > maxLength)
                    maxLength = k.length;
            }

            return maxLength;
        },

        TOKEN_KEYWORD : 1,

        TOKEN_STRING : 3,

        TOKEN_COMMENT_LINE : 6,

        TOKEN_COMMENT_BLOCK : 7,

        TOKEN_PUNCTUATION : 5,

        TOKEN_BRACKET_BLOCK : 4,

        TOKEN_IDENTIFIER : 99,

        /**
         * 查找Token。
         *
         * @param token
         * @param forward true 往后查找；false，往前查找
         * @param predicate 断言函数，格式为：function(token){ return true || false || null }，true 返回此token；false 继续查找；null 返回null。
         * @param onlySibling 可选（默认为false），是否仅在本级查找
         */
        findToken : function(token, forward, predicate, onlySibling)
        {
            if(onlySibling == undefined)
                onlySibling = false;

            var tmpToken = token;

            while(tmpToken)
            {
                var predicateResult = predicate(tmpToken);

                if(predicateResult == null)
                    return null;

                if(predicateResult == true)
                    return tmpToken;

                tmpToken = (forward ? tmpToken.next : tmpToken.prev);
            }

            if(!onlySibling && token && token.parent)
                return $.sqlAutocomplete.findToken(token.parent, forward, predicate, false);
            else
                return null;
        },

        /**
         * 查找SQL语句中指定位置的Token，如果指定位置不是Token，则返回前一个。
         *
         * @param tokens
         * @param sqlIndex SQL语句中的位置
         */
        findTokenBySqlIndex : function(tokens, sqlIndex)
        {
            if(!tokens || tokens.length < 1)
                return undefined;

            for(var i=0; i<tokens.length; i++)
            {
                var token = tokens[i];

                //在token起始位置
                if(token.startIndex == sqlIndex)
                    return token;
                //在token中
                else if(token.startIndex < sqlIndex && (token.endIndex == null || sqlIndex < token.endIndex))
                {
                    if($.sqlAutocomplete.isTokenBracketBlockWithValue(token))
                    {
                        var subToken = $.sqlAutocomplete.findTokenBySqlIndex(token.value, sqlIndex);

                        return (subToken || token);
                    }
                    else
                        return token;
                }
                //在token和token.next的中间
                else if(token.endIndex <= sqlIndex && token.next && token.next.startIndex > sqlIndex)
                {
                    return token;
                }
            }

            return null;
        },

        /**
         * 判断SQL语句中的位置是否在指定Token中。
         *
         * @param tokens
         * @param sqlIndex SQL语句中的位置
         */
        isInToken : function(token, sqlIndex)
        {
            return (token && token.startIndex <= sqlIndex && (token.endIndex == null || sqlIndex < token.endIndex));
        },

        /**
         * 判断token.value是否是指定字符串（忽略大小写）。
         *
         * @param token
         * @param textValue 可选，文本值
         */
        isTokenTextValue : function(token, textValue)
        {
            if(!token || typeof(token.value) != "string")
                return false;

            if(textValue == undefined)
                return true;

            if(token.value.length != textValue.length)
                return false;

            var upperValue = token.value.toUpperCase();

            if(upperValue == textValue)
                return true;

            return (upperValue == textValue.toUpperCase());
        },

        isTokenString : function(token)
        {
            return $.sqlAutocomplete.isTokenType(token, $.sqlAutocomplete.TOKEN_STRING);
        },

        /**
         * 是否是标识符Token。
         */
        isTokenIndentifier : function(token)
        {
            return $.sqlAutocomplete.isTokenType(token, $.sqlAutocomplete.TOKEN_IDENTIFIER);
        },

        /**
         * 是否是注释Token。
         */
        isTokenComment : function(token)
        {
            return $.sqlAutocomplete.isTokenType(token, $.sqlAutocomplete.TOKEN_COMMENT_LINE)
                || $.sqlAutocomplete.isTokenType(token, $.sqlAutocomplete.TOKEN_COMMENT_BLOCK);
        },

        /**
         * 是否不是注释Token。
         */
        isNotTokenComment : function(token)
        {
            return !$.sqlAutocomplete.isTokenComment(token);
        },

        /**
         * 是否是括弧块，并且有子Token。
         */
        isTokenBracketBlockWithValue : function(token)
        {
            if(!$.sqlAutocomplete.isTokenBracketBlock(token))
                return false;

            return (token.value && token.value.length > 0);
        },

        /**
         * 是否是括弧块。
         */
        isTokenBracketBlock : function(token)
        {
            return $.sqlAutocomplete.isTokenType(token, $.sqlAutocomplete.TOKEN_BRACKET_BLOCK);
        },

        /**
         * 是否是关键字。
         *
         * @param token
         * @param keywords 可选，指定关键字
         */
        isTokenKeyword : function(token, keywords)
        {
            if(!$.sqlAutocomplete.isTokenType(token, $.sqlAutocomplete.TOKEN_KEYWORD))
                return false;

            if(keywords == undefined)
                return true;

            return $.sqlAutocomplete.isKeyword(token.value, keywords);
        },

        /**
         * 是否是指定类型的Token。
         *
         * @param token
         * @param type
         */
        isTokenType : function(token, type)
        {
            return (token && token.type == type);
        },

        /**
         * Token是否已解析完成。
         */
        isTokenClosed : function(token)
        {
            return (token && token.endIndex != null);
        },

        /**
         * 从指定位置处解析Token数组。
         *
         * @param sql
         * @param tokens 用于存储解析结果的数组
         * @param startIndex 可选，起始位置，默认为0
         * @return 解析结束位置，sql.length 正确解析完成；<sql.length 遇到非法终止符，比如单独的右括弧、块注释结束符
         */
        resolveTokens : function(sql, tokens, startIndex)
        {
            if(startIndex == undefined)
                startIndex = 0;

            for(var i=startIndex; i< sql.length;)
            {
                var token = $.sqlAutocomplete.resolveToken(sql, i);

                //直到结束没有任何Token
                if(!token)
                    return sql.length;

                //Token没有结束
                if(token.endIndex == null)
                {
                    $.sqlAutocomplete.addTokenToArray(tokens, token);
                    return sql.length;
                }

                //既不是Token开始符、也不是关键字/标识符字符，比如')'
                if(token.startIndex == token.endIndex)
                    return token.endIndex;

                $.sqlAutocomplete.addTokenToArray(tokens, token);
                i = token.endIndex;
            }

            return sql.length;
        },

        /**
         * 将Token添加至数组，并建立链表关联。
         *
         * @param tokens 原数组
         * @param token 待追加的单个元素或者数组
         */
        addTokenToArray : function(tokens, token)
        {
            var prev = ((tokens.length - 1) >= 0 ? tokens[tokens.length - 1] : null);

            if(prev)
            {
                prev.next = token;
                token.prev = prev;
            }

            if(token.length)
            {
                for(var i=0; i<token.length; i++)
                    $.sqlAutocomplete.addTokenToArray(tokens, token[i]);
            }
            else
                tokens.push(token);
        },

        /**
         * 从指定位置处解析一个Token并返回。
         *
         * @param sql
         * @param startIndex
         * @param token 可选，需要继续解析的Token
         */
        resolveToken : function(sql, startIndex, token)
        {
            if(token)
            {
                if(token.startIndex == null)
                    throw new Error("illegal");

                if(token.endIndex != null)
                    ;
                else if($.sqlAutocomplete.TOKEN_KEYWORD == token.type)
                {
                    $.sqlAutocomplete.resolveTokenIdentifier(sql, startIndex, token);
                    token.type = $.sqlAutocomplete.TOKEN_KEYWORD;
                }
                else if($.sqlAutocomplete.TOKEN_STRING == token.type)
                {
                    $.sqlAutocomplete.resolveTokenString(sql, startIndex, token);
                }
                else if($.sqlAutocomplete.TOKEN_COMMENT_LINE == token.type)
                {
                    $.sqlAutocomplete.resolveTokenCommentLine(sql, startIndex, token);
                }
                else if($.sqlAutocomplete.TOKEN_COMMENT_BLOCK == token.type)
                {
                    $.sqlAutocomplete.resolveTokenCommentBlock(sql, startIndex, token);
                }
                else if($.sqlAutocomplete.TOKEN_PUNCTUATION == token.type)
                {
                    token.endIndex = startIndex;
                }
                else if($.sqlAutocomplete.TOKEN_BRACKET_BLOCK == token.type)
                {
                    $.sqlAutocomplete.resolveTokenBracketBlock(sql, startIndex, token);
                }
                else if($.sqlAutocomplete.TOKEN_IDENTIFIER == token.type)
                {
                    $.sqlAutocomplete.resolveTokenIdentifier(sql, startIndex, token);
                }
                else
                    throw new Error("unsupported");

                return token;
            }

            for(var i = startIndex; i < sql.length;)
            {
                var c = sql.charAt(i);
                var cn = (i+1) >= sql.length ? 0 : sql.charAt(i+1);

                var token = null;

                //字符串
                if(c == '\'')
                {
                    token = { startIndex : i };
                    $.sqlAutocomplete.resolveTokenString(sql, i+1, token);
                }
                //行注释
                else if((c == '-' && cn == '-') || (c =='/' && cn == '/'))
                {
                    token = { startIndex : i, value : (c == '-' ? "--" : "//") };
                    $.sqlAutocomplete.resolveTokenCommentLine(sql, i+2, token);
                }
                //块注释
                else if(c == '/' && cn == '*')
                {
                    token = { startIndex : i };
                    $.sqlAutocomplete.resolveTokenCommentBlock(sql, i+2, token);
                }
                //括弧块
                else if(c == '(')
                {
                    token = { startIndex : i };
                    $.sqlAutocomplete.resolveTokenBracketBlock(sql, i+1, token);
                }
                //标点符号
                else if(c == ',' || c == ';')
                {
                    token = { type : $.sqlAutocomplete.TOKEN_PUNCTUATION, startIndex : i, endIndex : i+1, value : c };
                }
                //标识符
                else if(!/\s/.test(c))
                {
                    token = { startIndex : i };
                    $.sqlAutocomplete.resolveTokenIdentifier(sql, i, token);

                    if($.sqlAutocomplete.isKeyword(token.value))
                        token.type = $.sqlAutocomplete.TOKEN_KEYWORD;
                }

                if(token)
                    return token;

                i += 1;
            }

            return null;
        },

        /**
         * 解析字符串。
         *
         * TOKEN_STRING 结构：
         * {
         * 		startIndex : Number, //起始位置
         * 		endIndex : Number, //结束位置，undefined表示未结束
         * 		value : String, //字符串内容
         * 		parent : Token, //父Token，undefined表示无父Token，否则仅可能为TOKEN_BRACKET_BLOCK
         * }
         *
         * 如果没有找到字符串结束符，token.endIndex将为undefined。
         *
         * @param sql
         * @param startIndex
         * @param token 要解析的Token，结构为：{ startIndex : Number }
         */
        resolveTokenString : function(sql, startIndex, token)
        {
            token.type = $.sqlAutocomplete.TOKEN_STRING;

            if(!token.value)
                token.value = "'";

            var chars = [];

            for(i = startIndex; i<sql.length; i++)
            {
                var c = sql.charAt(i);

                chars.push(c);

                if(c == '\'')
                {
                    var cn = (i+1) >= sql.length ? 0 : sql.charAt(i+1);

                    //转义字符
                    if(cn == '\'')
                    {
                        chars.push(cn);
                        i = i+1;
                    }
                    else
                    {
                        token.value = token.value + chars.join("");
                        token.endIndex = i+1;
                        chars = [];

                        break;
                    }
                }
            }

            //没有结束符
            if(chars.length > 0)
                token.value = token.value + chars.join("");
        },

        /**
         * 解析行注释。
         * 结构同TOKEN_STRING。
         * 如果没有找到行注释结束符，token.endIndex将为undefined。
         *
         * @param sql
         * @param startIndex
         * @param token 要解析的Token，结构为：{ startIndex : Number }
         */
        resolveTokenCommentLine : function(sql, startIndex, token)
        {
            token.type = $.sqlAutocomplete.TOKEN_COMMENT_LINE;

            if(!token.value)
                token.value = "--";

            var chars = [];

            for(i = startIndex; i<sql.length; i++)
            {
                var c = sql.charAt(i);

                if(c == '\n')
                {
                    token.value = token.value + chars.join("");
                    token.endIndex = i;
                    chars = [];

                    break;
                }
                else
                {
                    chars.push(c);
                }
            }

            //没有结束符
            if(chars.length > 0)
                token.value = token.value + chars.join("");
        },

        /**
         * 解析块注释。
         * 结构同TOKEN_STRING。
         * 如果没有找到块注释结束符，token.endIndex将为undefined。
         *
         * @param sql
         * @param startIndex
         * @param token 要解析的Token，结构为：{ startIndex : Number }
         */
        resolveTokenCommentBlock : function(sql, startIndex, token)
        {
            token.type = $.sqlAutocomplete.TOKEN_COMMENT_BLOCK;

            if(!token.value)
                token.value = "/*";

            var chars = [];

            for(i = startIndex; i<sql.length; i++)
            {
                var c = sql.charAt(i);

                chars.push(c);

                if(c == '*')
                {
                    var cn = (i+1) >= sql.length ? 0 : sql.charAt(i+1);

                    if(cn == '/')
                    {
                        chars.push(cn);

                        token.value = token.value + chars.join("");
                        token.endIndex = i+2;
                        chars = [];

                        break;
                    }
                }
            }

            //没有结束符
            if(chars.length > 0)
                token.value = token.value + chars.join("");
        },

        /**
         * 解析括弧块。
         *
         * TOKEN_STRING 结构：
         * {
         * 		startIndex : Number, //起始位置
         * 		endIndex : Number, //结束位置，undefined表示未结束
         * 		value : Token[], //子Token数组
         * 		parent : Token, //父Token，undefined表示无父Token，否则仅可能为TOKEN_BRACKET_BLOCK
         * }
         *
         * @param sql
         * @param startIndex
         * @param token 要解析的Token，结构为：{ startIndex : Number }
         */
        resolveTokenBracketBlock : function(sql, startIndex, token)
        {
            token.type = $.sqlAutocomplete.TOKEN_BRACKET_BLOCK;

            if(token.value && token.value.length > 0)
            {
                var tailToken = token.value[token.value.length - 1];

                if(tailToken.endIndex == null)
                    $.sqlAutocomplete.resolveToken(sql, startIndex, tailToken);

                for(var i=0; i<token.value.length; i++)
                    token.value[i].parent = token;

                if(tailToken.endIndex != null && tailToken.endIndex < sql.length && sql.charAt(tailToken.endIndex) == ')')
                    token.endIndex = tailToken.endIndex + 1;

                return;
            }

            token.value = [];
            var endIndex = $.sqlAutocomplete.resolveTokens(sql, token.value, startIndex);

            for(var i=0; i<token.value.length; i++)
                token.value[i].parent = token;

            if(endIndex < sql.length && sql.charAt(endIndex) == ')')
                token.endIndex = endIndex + 1;
        },

        /**
         * 解析标识符。
         * 结构同TOKEN_STRING，但是endIndex始终不会为undefined。
         *
         * @param sql
         * @param startIndex
         * @param token 要解析的Token，结构为：{ startIndex : Number }
         */
        resolveTokenIdentifier : function(sql, startIndex, token)
        {
            token.type = $.sqlAutocomplete.TOKEN_IDENTIFIER;

            if(token.value == null)
                token.value = "";

            var chars = [];

            for(i = startIndex; i<sql.length; i++)
            {
                var c = sql.charAt(i);

                var isEnd = (/[\s\,\;\(\)]/.test(c));

                //遇到“*/”，当sql不合法时可能
                if(!isEnd && c == '*')
                {
                    var cn = (i+1) >= sql.length ? 0 : sql.charAt(i+1);

                    if(cn == '/')
                        isEnd = true;
                }

                if(isEnd)
                {
                    token.value = token.value + chars.join("");
                    token.endIndex = i;
                    chars = [];

                    break;
                }
                else
                    chars.push(c);
            }

            //没有结束符
            if(chars.length > 0)
            {
                token.value = token.value + chars.join("");
                token.endIndex = sql.length;
            }
        }
    });

})
(jQuery);